// src/utils/httpClient.ts
import axios from 'axios';
import type { AxiosInstance, AxiosResponse, AxiosRequestConfig, InternalAxiosRequestConfig } from 'axios';
import router from '@/router';
import Message from '@/components/message';

// 扩展 Axios 类型以支持自定义属性
declare module 'axios' {
  export interface AxiosRequestConfig {
    retryCount?: number;
    retryLimit?: number;
    retryDelay?: number;
    showLoading?: boolean;
  }
}

export interface HttpResponse<T = unknown> {
  // 业务状态码，200-成功，其它-失败
  code: number;
  // 响应消息
  message: string;
  // 返回数据
  data: T;
  // 请求id
  requestId: string;
}

const apiClient: AxiosInstance = axios.create({
  baseURL: import.meta.env.VITE_API_BASE_URL,
  timeout: 5000,
});

// 创建源映射
const pendingRequests = new Map();

// 生成请求的唯一键
const getRequestKey = (config: AxiosRequestConfig): string => {
  const { url, method, params, data } = config;
  return [url, method, JSON.stringify(params), JSON.stringify(data)].join('&');
};

// 取消函数
const addPendingRequest = (config: AxiosRequestConfig): void => {
  const requestKey = getRequestKey(config);

  // 如果存在相同请求，则取消之前的请求
  if (pendingRequests.has(requestKey)) {
    const cancelToken = pendingRequests.get(requestKey);
    cancelToken.cancel(`重复请求: ${requestKey}`);
    pendingRequests.delete(requestKey);
  }

  // 创建新的取消令牌
  const source = axios.CancelToken.source();
  config.cancelToken = source.token;
  pendingRequests.set(requestKey, source);
};

// 移除请求
const removePendingRequest = (config: AxiosRequestConfig): void => {
  const requestKey = getRequestKey(config);
  pendingRequests.delete(requestKey);
};

// 跟踪活跃请求数量
let activeRequests = 0;

// 更新加载状态（简化版，不依赖外部store）
const updateLoading = (increment = true): void => {
  // 增加或减少活跃请求计数
  activeRequests = increment ? activeRequests + 1 : activeRequests - 1;

  // 这里可以通过控制台输出或者其他方式记录加载状态
  console.log(`Loading status: ${activeRequests > 0 ? 'true' : 'false'}`);

  // 如果将来需要整合 store，可以在这里添加
};

// 添加一个错误消息管理器
const errorMessageManager = {
  // 存储最近显示的错误消息及时间
  messages: new Map<string, number>(),

  // 显示时间窗口(毫秒)，在此时间内相同消息只显示一次
  timeWindow: 5000,

  // 显示错误消息
  showError(message: string): void {
    const now = Date.now();
    const key = message.trim();

    // 检查是否在时间窗口内已经显示过相同消息
    if (!this.messages.has(key) || now - (this.messages.get(key) || 0) > this.timeWindow) {
      // 显示消息
      Message.error(message);
      // 记录消息和时间
      this.messages.set(key, now);

      // 清理超过时间窗口的消息
      this.cleanup(now);
    }
  },

  // 清理过期的消息记录
  cleanup(now: number): void {
    for (const [key, timestamp] of this.messages.entries()) {
      if (now - timestamp > this.timeWindow) {
        this.messages.delete(key);
      }
    }
  }
};

apiClient.interceptors.request.use(
  (config: InternalAxiosRequestConfig) => {
    // 只在开发环境打印详细请求日志
    if (import.meta.env.DEV) {
      console.log(`[Request] ${config.method?.toUpperCase()} ${config.url}`, config);
    }

    // 添加请求到等待映射
    addPendingRequest(config);

    // 设置默认的重试次数 (使用类型断言解决类型错误)
    (config as any).retryCount = (config as any).retryCount || 0;
    (config as any).retryLimit = (config as any).retryLimit || 3;
    (config as any).retryDelay = (config as any).retryDelay || 1000;

    // 如果需要显示加载状态（默认为真）
    if ((config as any).showLoading !== false) {
      updateLoading(true);
    }

    return config;
  },
  (error) => {
    if (import.meta.env.DEV) {
      console.error('[Request Error]', error);
    }
    return Promise.reject(error);
  }
);

apiClient.interceptors.response.use(
  (response: AxiosResponse<HttpResponse>) => {
    // 请求完成后移除
    removePendingRequest(response.config);

    // 请求成功时更新加载状态
    if ((response.config as any).showLoading !== false) {
      updateLoading(false);
    }

    const { data } = response;

    // 业务状态码处理
    if (data.code !== 200) {
      // 处理业务错误
      errorMessageManager.showError(data.message || '请求失败');
      return Promise.reject(new Error(data.message || '未知错误'));
    }

    // 返回修改后的响应对象，而不是直接返回数据
    return response;
  },
  async (error) => {
    const config = error.config;

    if (axios.isCancel(error)) {
      // 请求被取消，通常不需要提示
      console.log('Request canceled:', error.message);
      return Promise.reject(error);
    }

    // 如果有config，尝试移除请求
    if (config) {
      removePendingRequest(config);

      // 请求出错时也需要更新加载状态
      if ((config as any).showLoading !== false) {
        updateLoading(false);
      }

      // 如果配置了重试且未达到重试限制，尝试重试
      if ((config as any).retryLimit && (config as any).retryCount < (config as any).retryLimit) {
        // 只有在网络错误或服务器错误(5xx)时重试
        if (!error.response || (error.response.status >= 500 && error.response.status <= 599)) {
          (config as any).retryCount += 1;

          // 延迟重试请求
          await new Promise((resolve) => {
            setTimeout(resolve, (config as any).retryDelay);
          });

          // 重新发送请求
          return apiClient(config);
        }
      }
    }

    // 网络错误
    if (!error.response) {
      errorMessageManager.showError('网络连接异常，请检查您的网络设置');
      return Promise.reject(error);
    }

    // 根据状态码区分处理
    const { status, data } = error.response;
    const errorMessage = data?.message || error.message || '服务器内部异常';

    switch (status) {
    case 400:
      errorMessageManager.showError(`请求参数错误: ${errorMessage}`);
      break;
    case 403:
      errorMessageManager.showError('您没有权限访问该资源');
      break;
    case 404:
      errorMessageManager.showError('请求的资源不存在');
      break;
    case 500:
      errorMessageManager.showError('服务器内部错误');
      // 只在第一次 500 错误时跳转
      if (!errorMessageManager.messages.has('服务器内部错误')) {
        router.push({
          name: 'error',
          params: {
            code: '500',
            title: '服务器错误',
            message: '抱歉，服务器出现了一些问题'
          }
        });
      }
      break;
    default:
      errorMessageManager.showError(`请求失败: ${errorMessage}`);
    }

    return Promise.reject(error);
  }
);

export default apiClient;
